
#include <iostream>
#include <string>
#include <unordered_map>
#include <functional>

template<typename C>
class AttributeData {
public:
	typedef void* C::* DataPtr;
	AttributeData(DataPtr data = nullptr) : m_data(data) {}

	template<typename T>
	void Set(C& instance, T value) { instance.*reinterpret_cast<T C::*>(m_data) = value; }
private:
	DataPtr m_data;
};

template<typename C> class AttributeMemberData;
template<typename C, typename T>
class AttributeMemberData<T C::*> : public AttributeData<C> {
public:
	AttributeMemberData(T C::* data) : AttributeData<C>(reinterpret_cast<void* C::*>(data)) {}
};

template<class C>
class AttributeFunction {
public:
	typedef void(C::* FunctionPtr)();
	AttributeFunction(FunctionPtr f) : m_function(f) {}
	template<typename R, typename... Args>
	R Invoke(C& instance, const Args&... args)
	{
		return (instance.*reinterpret_cast<R(C::*)(Args...)>(m_function))(args...);
	}
private:
	FunctionPtr m_function;
};

template<class T> class AttributeMemberFunction;
template<class R, class C, class... Args>
class AttributeMemberFunction<R(C::*)(Args...)> : public AttributeFunction<C> {
public:
	typedef R(C::* FunctionPtr)(Args...);
	AttributeMemberFunction(FunctionPtr f) : AttributeFunction<C>(reinterpret_cast<void(C::*)()>(f)) {}
};

template<typename C>
struct Reflect {
public:
	~Reflect() = default;
	static Reflect& GetInstance()
	{
		static Reflect reflect;
		return reflect;
	}

	template<typename T>
	Reflect* Regist(T C::* var, const std::string& name)
	{
		m_memberVars[name] = new AttributeMemberData<T C::*>(var);
		return this;
	}

	template<typename R, typename... Args>
	Reflect* Regist(R(C::* func)(Args...), const std::string& name)
	{
		m_memberFuns[name] = new AttributeMemberFunction<R(C::*)(Args...)>(func);
		return this;
	}

	template<typename R>
	void SetObjectAttribute(C& obj, std::string name, R val) { m_memberVars[name]->Set(obj, val); }

	template<typename R = void, typename... Args>
	R CallObjectFunction(C& obj, std::string name, Args... args)
	{
		return m_memberFuns[name]->template Invoke<R>(obj, args...);
	}

private:
	Reflect() = default;
	std::unordered_map <std::string, AttributeData<C>*> m_memberVars;
	std::unordered_map <std::string, AttributeFunction<C>*> m_memberFuns;
};